import numpy as np
import torch

tensor = torch.tensor([[1, 2, 3],
                       [4, 5, 6]])
"""
00torch.sum array.sum同理
"""
#按照第一个维度相加即列相加[5, 7, 9]
print("00",torch.sum(tensor,0)) #00 tensor([5, 7, 9])
#按照第二个维度相加即行相加[6,15]求和操作的结果维度总是比原始张量的维度少一维，因此
#如果你对二维张量的列（dim=1）求和，结果会以行的形式呈现，因为每一行都是对应着原始张
#量中的列求和的结果。
print("01",torch.sum(tensor,1)) #01 tensor([6, 15])
"""
01tensor.repeat
"""
#而 tensor.repeat(1, 2) 的意思是在第一个维度上重复一次，在第二个维度上重复两次。
# 所以最终结果的维度是 从(2, 3) -> (2, 6)  ps:重复一次等于不变
result = tensor.repeat(1, 2)
print("02",result) #02 tensor([[1, 2, 3, 1, 2, 3],
                   #           [4, 5, 6, 4, 5, 6]])
""" 
torch.cat拼接
"""
# 创建两个张量
#按行（维度 0）拼接时，张量的列数要相等。
#按列（维度 1）拼接时，张量的行数要相等。
#x为(2,2) y为(1,2)只能对行进行拼接
x = torch.tensor([[1, 2], [3, 4]])
y = torch.tensor([[5, 6]])
#不加dim参数默认从维度0连接
# 沿着行（维度0）拼接两个张量
result = torch.cat((x, y), dim=0)
print("03",result)#03 tensor([[1, 2],
                  #           [3, 4],
                  #           [5, 6]])
#沿着倒数第二个维度即行拼接
result = torch.cat((x, y), dim=-2)
print("04",result)#04 tensor([[1, 2],
                #             [3, 4],
                #             [5, 6]])

#torch.arange
# 创建一个从 0 到 4（不包括 5）的张量，默认步长为 1
x = torch.arange(5)
print("05",x)  # 输出: tensor([0, 1, 2, 3, 4])

# 创建一个从 2 到 10（不包括 11），步长为 2 的张量
y = torch.arange(2, 11, 2)
print("06",y)  # 输出: tensor([ 2,  4,  6,  8, 10])
#tensor.expand
# 创建一个张量
x = torch.tensor([[1, 2]])
#x为2*2 要扩展成2*4则行不变 列复制变大
# 将张量 x 扩展为 (1, 2)，自动填充维度为 (4, 2)，使之匹配目标形状
expanded_x = x.expand(4, 2)
print("07",expanded_x)
# 输出：
# tensor([[1, 2],
#         [1, 2],
#         [1, 2],
#         [1, 2]])

# 使用负值自动计算某个维度的大小，扩展为 (2, 2)，根据给定张量的形状自动填充
expanded_x = x.expand(2, -1)
print("08",expanded_x)
#tensor([[1, 2],
#        [1, 2]])
#view函数计算过程
"""
若有一个大小为 (2, 5, 3) 的张量，可以使用 view(-1, 3) 来将其重新整形为一个有3列的张量，PyTorch 会自动计算出行数为 (2*5)，即10。
对于大小为 (10, 20) 的张量，使用 view(5, -1) 将其重新整形为一个有5行的张量，PyTorch 会自动计算出列数为 (10*20)/5，即40。
对于大小为 (100,) 的张量，使用 view(-1, 10) 将其重新整形为一个有10列的张量，PyTorch 会自动计算出行数为 100/10，即10。
"""
#transpose
"""
tensor.transpose用于交换维度 例tensor.transpose(0, 2)第0个维度和第二个维度进行交换
"""
# 创建一个形状为 [3, 4, 5] 的张量
tensor = torch.randn(2, 3, 4)

# 将张量的维度从 [2, 3, 4] 变为 [4, 3, 2]
transpose_tensor = tensor.transpose(0, 2)
print("09",transpose_tensor.shape)  # 输出: torch.Size([4, 3, 2])
# 将张量的维度从 [2, 3, 4] 变为 [2, 4, 3]
transpose_tensor = tensor.transpose(1, 2)
print("10",transpose_tensor.shape)  # 输出: torch.Size([2, 4, 3])

#view和transpose
#view()是改变张量的形状，而不改变元素的存储方式，因此元素顺序不变。transpose()则是交换维度的顺序，会改变元素在张量中的位置。
tensor = torch.arange(24).reshape(2, 3, 4)
print("11原始",tensor)
"""
tensor = torch.arange(24).reshape(2, 3, 4)    tensor_view = tensor.view(2,-1,3)     tensor_transpose = tensor.transpose(1,2)   tensor_transpose = tensor.transpose(0,1)
([[[ 0,  1,  2,  3],                          ([[[ 0,  1,  2],                      ([[[ 0,  4,  8],                           ([[[ 0,  1,  2,  3], 
   [ 4,  5,  6,  7],                             [ 3,  4,  5],                         [ 1,  5,  9],                              [12, 13, 14, 15]], 
   [ 8,  9, 10, 11]],                            [ 6,  7,  8],                         [ 2,  6, 10],
                                                 [ 9, 10, 11]],                        [ 3,  7, 11]],                            [[ 4,  5,  6,  7],
  [[12, 13, 14, 15],                                                                                                              [16, 17, 18, 19]],
   [16, 17, 18, 19],                            [[12, 13, 14],                        [[12, 16, 20],
   [20, 21, 22, 23]]])                           [15, 16, 17],                         [13, 17, 21],                             [[ 8,  9, 10, 11],
                                                 [18, 19, 20],                         [14, 18, 22],                              [20, 21, 22, 23]]])
                                                 [21, 22, 23]]])                       [15, 19, 23]]])       
"""
tensor_view = tensor.view(2,-1,3) #(2,4,3)
print("12view",tensor_view)
"""
tensor([[[ 0,  1,  2],
         [ 3,  4,  5],
         [ 6,  7,  8],
         [ 9, 10, 11]],

        [[12, 13, 14],
         [15, 16, 17],
         [18, 19, 20],
         [21, 22, 23]]])
"""
tensor_transpose = tensor.transpose(1,2) #(2,4,3)
print("13transpose",tensor_transpose)
"""原始状态是按下标为2的维度从小到大依次输出 但下标为2的维度和下标为1的维度进行交换所以顺序也发生变换 现在按下标为1的维度从小到大依次输出
tensor([[[ 0,  4,  8],
         [ 1,  5,  9],
         [ 2,  6, 10],
         [ 3,  7, 11]],

        [[12, 16, 20],
         [13, 17, 21],
         [14, 18, 22],
         [15, 19, 23]]])
"""
tensor_transpose = tensor.transpose(0,1) #(2,4,3) 假设tensor为(batch,seq,emb)
print("14transpose",tensor_transpose)
"""
tensor([[[ 0,  1,  2,  3],
         [12, 13, 14, 15]],

        [[ 4,  5,  6,  7],                  
         [16, 17, 18, 19]],
     
        [[ 8,  9, 10, 11],
         [20, 21, 22, 23]]])
"""

#python的广播机制
tensor1 = torch.arange(24).reshape(2, 3, 4)
tensor2 = torch.arange(8).reshape(2, 1, 4)
print(tensor1)
print(tensor2)
"""  python广播机制
tensor1 (2,3,4)                    tensor2 (2,1,4)            tensor1+tensor2 广播机制会把tensor2扩维度从(2,1,4)扩展到(2,3,4) 
([[[ 0,  1,  2,  3],              ([[[0, 1, 2, 3]],              ([[[ 0,  2,  4,  6],
   [ 4,  5,  6,  7],                                                [ 4,  6,  8, 10],
   [ 8,  9, 10, 11]],               [[4, 5, 6, 7]]])                [ 8, 10, 12, 14]],

  [[12, 13, 14, 15],                                               [[16, 18, 20, 22],
   [16, 17, 18, 19],                                                [20, 22, 24, 26],
   [20, 21, 22, 23]]])                                              [24, 26, 28, 30]]])
"""
print("15广播机制",tensor1+tensor2)
#python的广播机制2
tensor = torch.arange(12).reshape(4,3)
#一个tensor变量加一个标量100 即把tensor中每一个元素和100相加
tensor +=100
"""
tensor                              tensor+=100
tensor([[ 0,  1,  2],               tensor([[100, 101, 102],
        [ 3,  4,  5],                       [103, 104, 105],
        [ 6,  7,  8],                       [106, 107, 108],
        [ 9, 10, 11]])                      [109, 110, 111]])
"""
print(16,tensor)

#torch.stack
# 创建两个1维张量
tensor1 = torch.tensor([1, 2, 3])
tensor2 = torch.tensor([4, 5, 6])
# 使用torch.stack进行堆叠默认行堆叠 tensor2+10python广播机制
result1 = torch.stack((tensor1, tensor2+10))
result2 = torch.stack((tensor1.view(3,1), tensor2.view(3,1)))
tensor = torch.tensor([1, 2, 3])
list = [tensor,tensor,tensor]
result3 = torch.stack(list,dim=1)
print(result3)
print("17",result1)
print("18",result2)
"""    
torch.stack((tensor1, tensor2+10))        result2 = torch.stack((tensor1.view(3,1), tensor2.view(3,1)))     result3 = torch.stack(list,dim=1)
result1:                                   result2:                                                          result3:
tensor([[1, 2, 3],                          tensor([[[1],                                                    tensor([[1, 1, 1],
  [14, 15, 16]])                                     [2],                                                            [2, 2, 2],
                                                     [3]],                                                           [3, 3, 3]])
                                                                                      
                                                    [[4],                                 
                                                     [5],                                 
                                                     [6]]])                                 
"""
# stack使用指定维度
tensor1 = torch.tensor([[1, 2], [3, 4]])
tensor2 = torch.tensor([[5, 6], [7, 8]])
# 在维度0上拼接张量
result1 = torch.stack((tensor1, tensor2), dim=0)
print(result1)
result2= torch.stack((tensor1, tensor2), dim=1)
print(result2)
"""
result1 = torch.stack((tensor1, tensor2), dim=0)                 result2= torch.stack((tensor1, tensor2), dim=1) 
tensor([[[1, 2],                                                tensor([[[1, 2],
         [3, 4]],                                                        [5, 6]],
      
        [[5, 6],                                                        [[3, 4],
         [7, 8]]])                                                       [7, 8]]]) 
"""
#torch.ones 创建一个全为1的矩阵
tensor2 = torch.ones(2, 3)
print("19",tensor2)
# 输出：
# tensor([[1., 1., 1.],
#         [1., 1., 1.]])

#torch.sqrt
D = torch.tensor([1.0, 4.0, 9.0])
print("20",torch.sqrt(D))  # 输出: tensor([1., 2., 3.])

#torch.nonzero()
tensor = torch.tensor([[0, 1, 0], [0, 0, 3], [4, 0, 0]])
# 使用 nonzero() 函数找到非零元素的索引
nonzero_indices = tensor.nonzero()
print("21",nonzero_indices)
"""
tensor([[0, 1],     第0行第1列元素为1，索引为(0,1)
        [1, 2],     第0行第3列元素为3，索引为(0,2)
        [2, 0]])    第3行第0列元素为4，索引为(2,0)
"""

#值比较
tensor = torch.arange(12).reshape(4,3)
#获取tensor变量中大于等于5的值 并一维输出
data = tensor[tensor>=5]
print("22",data)

#矩阵乘法torch.matmul
A = torch.tensor([1,2])
B = torch.tensor([[3],[4]])
result = torch.matmul(A,B)
print("23",result) #11
"""
[1,2] dot [3]  = 1*3+2*4 = 11
          [4]
"""
#torch.mean 计算张量的平均值
# 创建一个张量
tensor = torch.arange(12).reshape(4,3).float()
"""
tensor([[ 0,  1,  2],               
        [ 3,  4,  5],               
        [ 6,  7,  8],              
        [ 9, 10, 11]])   
"""
# 计算张量的均值 所有元素的和/所有元素个数
mean = torch.mean(tensor)
print("24",mean) #输出3. （0+11）*12/2/12=5.5
#求每一行的平均值
mean = torch.mean(tensor,dim=1)  #([ 1.,  4.,  7., 10.])
print("25",mean)
#按下标访问
tensor = torch.arange(12).reshape(4,3)
print("26",tensor[0])#输出第一行数据 tensor([0, 1, 2])

#torch.split
tensor = torch.tensor([1, 2, 3, 4, 5, 6])
# 将张量分割成大小为2的张量列表
result1 = torch.split(tensor, 2)
print("27",result1)  # 输出：[tensor([1, 2]), tensor([3, 4]), tensor([5, 6])]
# 将张量分割成大小不等的张量列表
result2 = torch.split(tensor, [2, 3, 1])
print("28",result2)  # 输出：[tensor([1, 2]), tensor([3, 4, 5]), tensor([6])]

tensor = torch.arange(12).reshape(4,3).float()
list = [tensor,tensor,tensor]
#训练出来三个矩阵 1.按照维度1拼接 2.按照维度1求平均 这样实现了三个矩阵的求平均
result1 = torch.stack(list,dim=1)
print("29",result1)
result2 = torch.mean(result1,dim=1)
print("30",result2)
"""
tensor:                  result1:                            result2:
([[ 0.,  1.,  2.],       tensor([[[ 0.,  1.,  2.],           tensor([[ 0.,  1.,  2.],
  [ 3.,  4.,  5.],                [ 0.,  1.,  2.],                   [ 3.,  4.,  5.],
  [ 6.,  7.,  8.],                [ 0.,  1.,  2.]],                  [ 6.,  7.,  8.],
  [ 9., 10., 11.]])                                                  [ 9., 10., 11.]])
                                 [[ 3.,  4.,  5.],
                                  [ 3.,  4.,  5.],
                                  [ 3.,  4.,  5.]],
                         
                                 [[ 6.,  7.,  8.],
                                  [ 6.,  7.,  8.],
                                  [ 6.,  7.,  8.]],
                         
                                 [[ 9., 10., 11.],
                                  [ 9., 10., 11.],
                                  [ 9., 10., 11.]]])
"""
#生成5个随机数 每个随机数范围为[0,10-1]
users = np.random.randint(0, 10, 5)
print("31",users)#[1 3 7 8 2]

#np.random.shuffle 是 NumPy 库中的一个函数，用于随机打乱一个数组的顺序。
# 创建一个数组
arr = np.array([1, 2, 3, 4, 5])
# 打乱数组的顺序
np.random.shuffle(arr)
print("32",arr) #输出可能是[2 4 5 1 3] 因为是随机的

#np.arange
arr = np.arange(5)
print(arr)  # 输出: [0 1 2 3 4]
arr = np.arange(0, 10, 2)  # 从0开始，到10结束（不包括10），步长为2
print(arr)  # 输出: [0 2 4 6 8]
import numpy as np
# 生成一个3x3的矩阵，元素从0到8（共9个）
matrix = np.arange(9).reshape(3, 3)
print(matrix)  # 输出:
# [[0 1 2]
#  [3 4 5]
#  [6 7 8]]
print("---------------------------------------")

#按下标访问但输入的下标是numpy数组类型
list = np.array([1,2,1])
array = np.array([[1,2,3],[4,5,6]])
#依次获取 array[1][1] array[1][2] array[1][1]数据
result = array[1][list]
print("33",result) #[5 6 5]

#torch.topk() 返回的两个值中，第一个是每行最大的2个值，第二个是这些最大值的索引
t = torch.tensor([[7, 2, 3],
         [4, 10, 6],
         [7, 8, 19]])
max_k, rating_K = torch.topk(t, k=2)
print("34",max_k,"\n",rating_K)
"""
tensor([[ 7,  3],               tensor([[0, 2],
        [10,  6],                       [1, 2],
        [19,  8]])                      [2, 1]])
"""
# #tensorboard绘图工具使用
# from tensorboardX import SummaryWriter
# #将记录的文件放在./logs文件夹下
# writer = SummaryWriter("logs")
# for i in range(100):
#     #第一个参数为图像标题 第二个参数为y 第三个参数为x
#     writer.add_scalar("y=2x",2*i,i)
# writer.close()
# #训练完后打开pycharm的terminal输入如下指令 --logdir指定log文件夹 port指定端口号
# #tensorboard --logdir=logs --port=6007

#torch.diag对角矩阵工具包
#输入是一维数据时创建对角矩阵
diagonal = torch.diag(torch.tensor([1, 2, 3]))
print("35",diagonal)
"""
tensor([[1, 0, 0],
        [0, 2, 0],
        [0, 0, 3]])
"""
#输入时二维数据时提取张量的对角元素
diagonal_elements = torch.diag(diagonal)
print("36",diagonal_elements)
"""
tensor([1, 2, 3])
"""

#利用L2范式求两个向量余弦相似度
import torch.nn.functional as F
view1 = torch.tensor([[1,2,3]]).float()
view2 = torch.tensor([[1,2,4]]).float()
#F.normalize默认L2归一化
"""
L2归一化 例 a :[1,2,3] b :[1,2,3] 
1.计算模长  a的模为(1^2+2^2+3^2)^0.5=14^0.5 b的模(1^2+2^2+4^2)^0.5=21^0.5
2.L2归一化: 向量中每个元素除以向量的模长 以a为例 L2后的a [1/14^0.5 , 2/14^0.5 , 3/14^0.5]
"""
view1, view2 = F.normalize(view1), F.normalize(view2)
#@是矩阵点乘操作符 view2.T为转置符号
pos_score = view1 @ view2.T
print("37",pos_score)


a =	torch.tensor([[0, 1],
        [1, 2],])
#第一行和第零行交换位置
a = a[[1,0]]
print("38",a)

#tensor对应元素相乘和点乘
tensor1 = torch.tensor([[1,2],
                        [3,2]])
tensor2 = torch.tensor([[1,2],
                        [2,1]])
#*为对应元素相乘 也可以使用torch.mul(tensor1,tensor2)
print("39",tensor1*tensor2)
#@为点乘 也可以使用torch.matmul(tensor1,tensor2)
print("40",tensor1 @ tensor2)

#named_parameters()寻找模型的可训练参数
#nn.Parameter将tensor变量变为可训练参数
import torch.nn as nn
class SimpleModel(nn.Module):
    def __init__(self):
        super(SimpleModel, self).__init__()
        #调用nn.Parameter 即a会在模型训练的时候反向传播
        #使用nn.Parameter不会改变初始值
        self.a = nn.Parameter(torch.Tensor([[1,2],[3,4]]))
        print("41",self.a)
        #nn.ParameterDict可以看作是一个容器，用于存储可训练的参数 创建一个字典 同样也不会改变初始值
        self.embedding_dict = nn.ParameterDict({
            'b': nn.Parameter(torch.Tensor([[1,1],[1,1]])),
            'c': nn.Parameter(torch.Tensor([[2,2],[2,2]])),
        })
        #不调用nn.Parameter 及时设置为requires_grad=True也不会被模型认为是可学习参数
        self.b = torch.rand((2, 2), requires_grad=True)

model = SimpleModel()
print("41",model.a)
print("41",model.embedding_dict['b'])
print("41",model.embedding_dict['c'])
"""
parameter不改变初始值
a:
tensor([[1., 2.],
        [3., 4.]], requires_grad=True)
b:
tensor([[1., 1.],
        [1., 1.]], requires_grad=True)
c:
tensor([[2., 2.],
        [2., 2.]], requires_grad=True)
"""
for name, param in model.named_parameters():
    print("42",name)  # 打印参数名称
"""
42 a
42 embedding_dict.b
42 embedding_dict.c
"""

"""
1.train_dataset[(user_id,item_id)*1437540]
2.按照数组每个元素的第一个值进行从小到大排序 即按user_id从小到大对train_dataset重新排序
3.
	train_dataset[:, 0]提取train_dataset所有行中第一列元素
	np.argsort(train_dataset[:, 0]) 返回一个数组，该数组包含能使原始数组排序的索引。对于数值数组，它会返回使得数组从小到大排序的索引。
	train_dataset[sorted_indices] 使用sorted_indices作为索引来重新排列train_dataset的行
	reshape(train_dataset.shape): 重塑数组的形状使其与原始train_dataset的形状相同。
"""
train_dataset=np.array([[1, 2], [5, 6],[3, 4], [9, 10],[7, 8]])
sorted_indices = np.argsort(train_dataset[:, 0])
sorted_temp = train_dataset[sorted_indices].reshape(train_dataset.shape)
print("43",sorted_temp)
"""
43:
[[ 1  2]
 [ 3  4]
 [ 5  6]
 [ 7  8]
 [ 9 10]]
"""

#concatenate在numpy数组底部添加一行
arr = np.array([[1, 2], [3, 4], [5, 6]])
new_row = [7, 8]
# 在底部添加新行
arr = np.concatenate((arr, [new_row]))
print("44",arr)

#np.vstack垂直堆叠 np.hstack水平堆叠 效果类似cat
a = np.array([[5, 6]])
b = np.array([[7, 8]])
result1 = np.vstack((a, b))
result2 = np.hstack((a, b))
"""
np.vstack((a, b)):
                    [[5 6]
                     [7 8]]
np.hstack((a, b)):
                    [[5 6 7 8]]
"""
print("45",result1)
print("46",result2)

#数组位置交换
row = [1,2,3]
col = [4,5,6]
row, col = [row, col], [col, row]
print("47",row)
print("48",col)
"""
47 [[1, 2, 3], [4, 5, 6]]
48 [[4, 5, 6], [1, 2, 3]]
"""
row = torch.LongTensor(row).view(-1)
# 49 tensor([1, 2, 3, 4, 5, 6])
print("49",row)

#torch.cat进阶 将列表中所有tensor进行cat拼接
a=[]
b = torch.tensor([(1,2,3),(3,4,5),(5,6,7)])
c = torch.tensor([(1,2,3),(3,4,5),(5,6,7)])
d = torch.tensor([(1,2,3),(3,4,5),(5,6,7)])
a.append(b)
a.append(c)
a.append(d)
a = torch.cat(a,dim=1)
print("50",a)
"""
([[1, 2, 3, 1, 2, 3, 1, 2, 3],
  [3, 4, 5, 3, 4, 5, 3, 4, 5],
  [5, 6, 7, 5, 6, 7, 5, 6, 7]])
"""




